﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Timtopia.DGMLPosterView
{
    public class Parser
    {
        public static void FindFirstMatchingBrackets(string s, out int start, out int length)
        {
            int level = start = length = -1;
            for (int i = 0; i < s.Length; ++i)
            {
                if (s[i] == '(' && ++level == 0)
                    start = i + 1;
                else if (s[i] == ')' && level >= 0 && level-- == 0)
                {
                    length = i - start;
                    break;
                }
            }
        }

        /// <summary>
        /// Node expression is:
        ///   type[label](children)
        /// </summary>
        private static Regex NodeLabelRE = new Regex(@"^[^\[]*\[([^\]]*)\]");

        /// <summary>
        /// Parse the given string for the first node and its children if any.
        /// The string is assumed to be one node and its children 
        /// or a ';' separated list of nodes (possibly with their own children).
        /// </summary>
        /// <param name="s">string to parse</param>
        /// <returns>the node</returns>
        public static Node ParseNode(string s)
        {
            string r;
            return ParseNode(s, out r);
        }

        /// <summary>
        /// Parse the given string for the first node and its children if any.
        /// The string is assumed to be one node and its children 
        /// or a ';' separated list of nodes (possibly with their own children).
        /// </summary>
        /// <param name="s">string to parse</param>
        /// <param name="r">remainder of the string after extracting the node</param>
        /// <returns>the node</returns>
        public static Node ParseNode(string s, out string r)
        {
            var l = NodeLabelRE.Match(s).Groups[1];
            int end = l.Index + l.Length;
            Node node = new Node {
                Label = l.ToString()
            };
            int startChildren, lengthChildren;
            FindFirstMatchingBrackets(s, out startChildren, out lengthChildren); // look for a list of children on this node
            if (startChildren < s.IndexOf(';') // do the brackets belong to this node in the list?
                && lengthChildren > 0 // is there anything in the brackets?
                )
            {
                string children = s.Substring(startChildren, lengthChildren);
                ParseChildren(node, children);
                end = startChildren + lengthChildren + 1;
            }
            r = "";
            if (s.Length > end + 1)
            {
                r = s.Substring(end);
            }
            return node;
        }

        /// <summary>
        /// Populate the children of the given node by parsing the given string
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="children">a semicolon separated list of nodes</param>
        public static void ParseChildren(Node parent, string children)
        {
            int nextSemicolon = 0;
            while (nextSemicolon >= 0)
            {
                string remainder;
                parent.Children.Add(ParseNode(children, out remainder));
                nextSemicolon = remainder.IndexOf(';');
                children = remainder.Substring(nextSemicolon + 1);
            }
        }

        public static void PrintTree(Node v, int depth)
        {
            for (int i = 0; i < depth; i++)
            {
                Console.Write("-");
            }
            Console.WriteLine(v.Label);
            foreach (var c in v.Children)
            {
                PrintTree(c, depth + 1);
            }
        }

        public static string CommonPrefix(IEnumerable<string> strings)
        {
            string prefix = "";
            int i = 0;
            while (strings.Any())
            {
                int c = -1;
                foreach (var s in strings)
                {
                    if (s.Length <= i)
                    {
                        goto Done;
                    }
                    if (c < 0)
                    {
                        c = s[i];
                    }
                    else if (s[i] != c)
                    {
                        goto Done;
                    }
                }
                prefix += (char)c;
                ++i;
            }
        Done:
            return prefix;
        }
    }

    public class Node
    {
        public string Label;
        public List<Node> Children = new List<Node>();
    }
}
